import json
import random
import time

import re
import requests

from selenium import webdriver

"""
    微信公众号地址: https://mp.weixin.qq.com 需注册用于登录的账号
    单线程执行
    实现微信登录/访问搜索公众号及其下文章 这里没有爬取评论
    ps: 搜索输入关键字查询到的第一个公众号下的文章
"""


def wechat_login():
    # 用webdriver启动谷歌浏览器
    print("启动浏览器, 打开微信公众号登录界面")
    driver = webdriver.Chrome()
    driver.get("https://mp.weixin.qq.com/")

    time.sleep(2)
    # 页面标题
    print(driver.title)

    print("正在输入微信公众号登录账号和密码")
    # 清空账号框中的内容
    driver.find_element_by_name("account").clear()
    driver.find_element_by_name("account").send_keys(input("请输入账号: "))
    time.sleep(1)
    driver.find_element_by_name("account").clear()
    driver.find_element_by_name("password").send_keys(input("请输入密码: "))

    # 在自动输完密码后需要手动点下记住我
    # print("请在登录界面点击: 记住账号")
    # driver.find_element_by_class_name("frm_checkbox_label").click()
    # time.sleep(5)

    # 自动点击登录按钮进行登录
    driver.find_element_by_class_name("btn_login").click()

    # 拿手机扫描二维码
    print('请拿手机扫描二维码登录公众号')
    time.sleep(20)
    print("登录成功")

    cookies = driver.get_cookies()
    # 获取cookies
    cookie_items = driver.get_cookies()
    # print(cookie_items)

    post = {}  # 用于提取cookies的字典

    # 获取到的cookies是列表形式, 提取cookies转成json形式并存入本地名为cookie的文本中
    for cookie_item in cookie_items:
        post[cookie_item["name"]] = cookie_item['value']
    cookie_str = json.dumps(post)
    with open("cookie.txt", "w+", encoding="utf-8") as f:
        f.write(cookie_str)
    print("cookies信息已保存在本地文件中")


# 爬取微信公众号文章, 并存在本地文本中

def get_content(query):
    # query 为要爬取的公众号名称
    # 公共号主页
    url = "https://mp.weixin.qq.com"

    # 设置headers
    headers = {
        "HOST": "mp.weixin.qq.com",
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
    }

    from requests.packages import urllib3
    urllib3.disable_warnings()  # 关闭警告

    # 读取上一步获取到的cookies
    with open("cookie.txt", "r", encoding="utf-8") as f:
        cookie = f.read()
    cookies = json.loads(cookie)

    # 增加重试连接次数
    session = requests.Session()
    session.keep_alive = False
    # 增加重试连接次数
    session.adapters.DEFAULT_RETRIES = 511
    time.sleep(5)

    # 登录之后的微信公众号首页url变化为: https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN&token=1938280528 该地址可由发起登录后的response.url获取, 再从这里获取token信息
    response = session.get(url=url, cookies=cookies, verify=False)
    token = re.findall(r'token=(\d+)', str(response.url))[0]
    time.sleep(2)

    # 搜索微信公众号的接口地址 请求 URL: https://mp.weixin.qq.com/cgi-bin/searchbiz?action=search_biz&token=1584963579&lang=zh_CN&f=json&ajax=1&random=0.10389338621286081&query=python&begin=0&count=5
    search_url = "https://mp.weixin.qq.com/cgi-bin/searchbiz?"
    # 搜索微信公众号接口需要传入的参数:微信公众号token/随机数random/搜索的微信公众号名字query
    query_str = {
        "action": "search_biz",
        "token": token,
        "lang": "zh_CN",
        "f": "json",
        "ajax": "1",
        "random": random.random(),
        "query": query,
        "begin": 0,
        "count": 5
    }
    # 打开搜索微信公众号接口地址并发起请求,需要传入相关参数信息如: cookies/params/headers
    search_response = session.get(
        search_url,
        cookies=cookies,
        headers=headers,
        params=query_str
    )
    # print("响应正文---", search_response.json())

    # 取搜索结果中的第一个公众号
    lists = search_response.json().get('list')[0]
    print(lists)
    fakeid = lists.get('fakeid')

    # 微信公众号文章接口地址 请求 URL: https://mp.weixin.qq.com/cgi-bin/appmsg?token=1584963579&lang=zh_CN&f=json&ajax=1&random=0.5252288090181953&action=list_ex&begin=0&count=5&query=python&fakeid=MzIxNjM4NDE2MA%3D%3D&type=9
    appmsg_url = "https://mp.weixin.qq.com/cgi-bin/appmsg?"
    # 搜索文章需要传入几个参数: 登录公众号token/要爬取文章的公众号fakeid/随机数random
    query_str_data = {
        'token': token,
        'lang': 'zh_CN',
        'f': 'json',
        'ajax': '1',
        'random': random.random(),
        'action': 'list_ex',
        'begin': '0',  # 不同页，此参数变化，变化规则为每页加5
        'count': '5',
        'query': '',
        'fakeid': fakeid,
        'type': '9'
    }
    # 打开搜索的微信公众号文章列表
    appmsg_response = session.get(
        appmsg_url,
        cookies=cookies,
        headers=headers,
        params=query_str_data
    )
    # 获取文章总数
    max_num = appmsg_response.json().get('app_msg_cnt')
    # 每页至少有5条, 获取文章总的页数, 怕趋势需要分页爬
    num = int(int(max_num) / 5)  # 文章页数
    # 起始页begin参数, 往后每页加5
    begin = 0
    seq = 0  # 文章数目计数
    while num + 1 > 0:
        query_str_data = {
            'token': token,
            'lang': 'zh_CN',
            'f': 'json',
            'ajax': '1',
            'random': random.random(),
            'action': 'list_ex',
            'begin': '{}'.format(str(begin)),  # 对begin格式化
            'count': '5',
            'query': '',
            'fakeid': fakeid,
            'type': '9'
        }
        print('正在翻页:-------', begin)
        time.sleep(5)

        # 获取每一页文章的标题和链接地址, 并写入本地文本中
        query_fakeid_response = requests.get(
            appmsg_url,
            cookies=cookies,
            headers=headers,
            params=query_str_data
        )
        fakeid_list = query_fakeid_response.json().get('app_msg_list')
        if fakeid_list:
            for item in fakeid_list:
                content_link = item.get('link')
                content_title = item.get('title')
                filename = query + '.txt'
                seq += 1
                with open(filename, "a", encoding="utf-8") as fh:
                    fh.write(str(seq) + "|" + content_title + "|" + content_link + "\n")
        num -= 1
        begin = int(begin)
        begin += 5


if __name__ == "__main__":
    # 登录微信公众号, 获取登录之后的cookies信息, 并保存到本地文本中
    wechat_login()
    query = input("请输入需要查找的公众号: ") # 这里获取输入query查询到的第一个公众号
    print("开始爬取公众号: " + query)
    get_content(query)
    print("爬取完成")
